﻿using Nemerle;
using Nemerle.Collections;
using Nemerle.Text;
using Nemerle.Utility;
using PT = Nemerle.Compiler.Parsetree;

using System;
using System.IO;
using System.Reflection;
using SCG = System.Collections.Generic;
using System.Web.Mvc;
using System.Web.Routing;

namespace System.Web.Mvc
{
  internal class ViewEngineHost
  {
    view_engine : ProjectViewEngine;
    project_path : string;

    public this(project_path : string)
    {
        view_engine = ProjectViewEngine(project_path);
        this.project_path = project_path;
    }

    public FindView(controller : string, view : string, _master : string) : bool * string
    {
      def ctx = ControllerContext();
      ctx.RouteData = {
        def route_data = RouteData();
        route_data.Values.Add("controller", controller);
        route_data
      };

      def result = view_engine.FindView(ctx, view);
      match(result) {
        | null => (false, "")
        | view => (true, view)
      }
    }
  }
  
  internal class ProjectViewEngine
  {
    project_path : string;
    
    public this(project_path : string)
    {
      this.project_path = Path.GetFullPath(project_path);
    }
    
    public FindView(ctx : ControllerContext, view : string) : string
    {
        def controller = ctx.RouteData.Values["controller"];
        def searchPatterns = [
            $"~/Views/$controller/$view",
            $"~/Views/Shared/$view",
        ];
        
        try
        {
            match (searchPatterns.Map(AnyFile(_)).Find(_ != null))
            {
                | Some(x) => x
                | None => null
            }
        }
        catch
        {
            | _ is DirectoryNotFoundException => null
        }
    }

    protected AnyFile(virtualPath : string) : string
    {
      def path = regexp match(virtualPath) {
        | @"~/(?<path>.*)" => path
        | _ => virtualPath
      }
      def full_path = Path.Combine(project_path, path);
      def dir = Path.GetDirectoryName(full_path);
      def file = Path.GetFileName(full_path);
      
      match (Directory.GetFiles(dir, file + ".*"))
      {
          | null 
          | a when a.Length == 0 => null
          | a => 
              a[0].Substring(project_path.Length + 1); // remove absolute path part
      }
    }
  }
}
